package ar.camera.globject;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.Arrays;
import java.util.List;

import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.opengl.GLUtils;
import ar.activity.R;
import ar.camera.pojo.GLLocation;
import ar.camera.pojo.GLPoint;
import ar.camera.pojo.GeoLocation;
import ar.globals.Globals;
import ar.utils.LocationUtils;

public class MiniMap {

	private List<GLLocation> mListOfGLLocations;
	private GLLocation mCrrLct;
	private FloatBuffer vertexBuffer;
	private FloatBuffer viewVertexBuffer;
	private float deltaX = 0.5f;
	private float deltaY = 0.5f;
	private float deltaZ = 0f;
	private float centerX = -2.7f;
	private float centerY = 1.4f;
	private float centerZ = 0f;

	private boolean isLoadedTexture;

	public boolean isLoadedTexture() {
		return isLoadedTexture;
	}

	public void setmListOfGLLocations(List<GeoLocation> mListOfGeoLocations,
			GeoLocation geoCurr) {
		this.mListOfGLLocations = LocationUtils
				.convertFromListOfGeoLocationsToListOfGLLocations(
						mListOfGeoLocations, geoCurr, 1000);
	}

	private float vertices[] = {
			// List of vertices
			centerX - deltaX, centerY - deltaY, centerZ - deltaZ, // V1-bottomleft
			centerX - deltaX, centerY + deltaY, centerZ - deltaZ, // V2-topleft
			centerX + deltaX, centerY - deltaY, centerZ - deltaZ, // V3-bottomright
			centerX + deltaX, centerY + deltaY, centerZ - deltaZ // V4-topright
	};
	private float originalVertices[] = new float[12];
	private float viewVertices[] = new float[12];

	private FloatBuffer textureBuffer;
	private FloatBuffer viewTextureBuffer;
	private float texture[] = {
			// Mapping coordinates for the vertices
			0.0f, 1.0f, // top left (V2)
			0.0f, 0.0f, // bottom left (V1)
			1.0f, 1.0f, // top right (V4)
			1.0f, 0.0f // bottom right (V3)
	};
	private float viewTexture[] = {
			// Mapping coordinates for the vertices
			0.0f, 1.0f, // top left (V2)
			0.0f, 0.0f, // bottom left (V1)
			1.0f, 1.0f, // top right (V4)
			1.0f, 0.0f // bottom right (V3)
	};

	private int[] textures = new int[1];
	private int[] viewTextures = new int[1];

	public MiniMap() {
		ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
		byteBuffer.order(ByteOrder.nativeOrder());
		vertexBuffer = byteBuffer.asFloatBuffer();
		vertexBuffer.put(vertices);
		vertexBuffer.position(0);

		byteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
		byteBuffer.order(ByteOrder.nativeOrder());
		textureBuffer = byteBuffer.asFloatBuffer();
		textureBuffer.put(texture);
		textureBuffer.position(0);

		byteBuffer = ByteBuffer.allocateDirect(viewVertices.length * 4);
		byteBuffer.order(ByteOrder.nativeOrder());
		viewVertexBuffer = byteBuffer.asFloatBuffer();
		viewVertexBuffer.put(viewVertices);
		viewVertexBuffer.position(0);

		byteBuffer = ByteBuffer.allocateDirect(viewTexture.length * 4);
		byteBuffer.order(ByteOrder.nativeOrder());
		viewTextureBuffer = byteBuffer.asFloatBuffer();
		viewTextureBuffer.put(viewTexture);
		viewTextureBuffer.position(0);

		originalVertices = Arrays.copyOfRange(vertices, 0, vertices.length);
		viewVertices = Arrays.copyOfRange(originalVertices, 0,
				originalVertices.length);
		isLoadedTexture = false;
		mCrrLct = new GLLocation(0, 0, 0, null);
	}

	public void loadGLTexture(GL10 gl, Context context, GLPoint eye, GLPoint cam) {

		InputStream is = context.getResources().openRawResource(
				R.drawable.compass);
		Bitmap bitmap;
		try {
			bitmap = BitmapFactory.decodeStream(is);
		} finally {
			try {
				is.close();
			} catch (IOException e) {
				// Ignore.
			}
		}
		Bitmap bmOverlay = Bitmap.createBitmap(bitmap.getWidth(),
				bitmap.getHeight(), bitmap.getConfig());

		Canvas canvas = new Canvas(bmOverlay);
		Paint paint = new Paint();
		paint.setColor(Color.CYAN);
		paint.setFlags(Paint.ANTI_ALIAS_FLAG);

		canvas.drawBitmap(bitmap, 0, 0, paint);

		float radius = 62;
		float center = 64;
		float maxDist = Globals.RADIUS / 1000f;

		for (int i = 0; i < mListOfGLLocations.size(); i++) {
			GLLocation tmp = mListOfGLLocations.get(i);
			float x0 = (tmp.x - eye.x);
			float y0 = (tmp.z - eye.z);
			float alpha = (float) Math.atan(y0 / x0);
			float d = LocationUtils.distFrom(eye.x, tmp.x, eye.z, tmp.z);

			float cx = (float) (Math.abs(Math.cos(alpha)) * d / maxDist * radius)
					* x0 * (-1) / Math.abs(x0);
			float cy = (float) (Math.abs(Math.sin(alpha)) * d / maxDist * radius)
					* y0 * (-1) / Math.abs(y0);
			if (Math.abs(cx) <= radius && Math.abs(cy) <= radius) {
				canvas.drawCircle(cx + center, cy + center, 2.5f, paint);
			}
		}
		// draw current location icon
		float tmpX = (mCrrLct.x - eye.x);
		float tmpY = (mCrrLct.z - eye.z);
		float alpha = (float) Math.atan(tmpY / tmpX);
		float d = LocationUtils.distFrom(eye.x, mCrrLct.x, eye.z, mCrrLct.z);
		float currX = (float) (Math.abs(Math.cos(alpha)) * d / maxDist * radius)
				* tmpX * (-1) / Math.abs(tmpX);
		float currY = (float) (Math.abs(Math.sin(alpha)) * d / maxDist * radius)
				* tmpY * (-1) / Math.abs(tmpY);
		if (Math.abs(currX) <= radius && Math.abs(currY) <= radius) {
			paint.setColor(Color.RED);
			canvas.drawCircle(currX + center, currY + center, 3f, paint);
		}

		gl.glGenTextures(1, textures, 0);
		gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
				GL10.GL_NEAREST);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
				GL10.GL_LINEAR);

		GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmOverlay, 0);
		gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		gl.glEnable(GL10.GL_BLEND);

		bitmap.recycle();
		isLoadedTexture = true;

		// Load Compass View
		InputStream vis = context.getResources().openRawResource(
				R.drawable.compass_view);
		Bitmap vBitmap;
		try {
			vBitmap = BitmapFactory.decodeStream(vis);
		} finally {
			try {
				vis.close();
			} catch (IOException e) {
			}
		}
		Bitmap vbmOverlay = Bitmap.createBitmap(vBitmap.getWidth(),
				vBitmap.getHeight(), Bitmap.Config.ARGB_8888);
		// create a canvas on which to draw
		Canvas vCanvas = new Canvas(vbmOverlay);
		Paint vPaint = new Paint();
		vPaint.setAlpha(90);
		vPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
		vCanvas.drawBitmap(vBitmap, 0, 0, vPaint);

		gl.glGenTextures(1, viewTextures, 0);
		gl.glBindTexture(GL10.GL_TEXTURE_2D, viewTextures[0]);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
				GL10.GL_NEAREST);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
				GL10.GL_LINEAR);

		GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, vbmOverlay, 0);
		gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		gl.glEnable(GL10.GL_BLEND);

		vBitmap.recycle();
	}

	public void draw(GL10 gl) {
		ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
		byteBuffer.order(ByteOrder.nativeOrder());
		vertexBuffer = byteBuffer.asFloatBuffer();
		vertexBuffer.put(vertices);
		vertexBuffer.position(0);

		gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		gl.glFrontFace(GL10.GL_CW);
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);

		gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);

		// Draw Compass View
		// =====================================================
		byteBuffer = ByteBuffer.allocateDirect(viewVertices.length * 4);
		byteBuffer.order(ByteOrder.nativeOrder());
		viewVertexBuffer = byteBuffer.asFloatBuffer();
		viewVertexBuffer.put(viewVertices);
		viewVertexBuffer.position(0);

		gl.glBindTexture(GL10.GL_TEXTURE_2D, viewTextures[0]);
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		gl.glFrontFace(GL10.GL_CW);
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, viewVertexBuffer);
		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, viewTextureBuffer);
		gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, viewVertices.length / 3);
		// =====================================================

		// Disable the client state
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
	}

	public void updateVertices(float azimut) {

		azimut = (float) (azimut * Math.PI / 180);

		for (int i = 0; i <= 9; i += 3) {
			vertices[i] = originalVertices[i] - centerX;
			vertices[i + 1] = originalVertices[i + 1] - centerY;
		}
		// x' = x cos a -y sin a
		// y' = x sin a + y cos a
		for (int i = 0; i <= 9; i += 3) {
			float x0 = vertices[i];
			float y0 = vertices[i + 1];
			vertices[i] = (float) (x0 * Math.cos(azimut) - y0
					* Math.sin(azimut));
			vertices[i + 1] = (float) (x0 * Math.sin(azimut) + y0
					* Math.cos(azimut));
		}
		for (int i = 0; i <= 9; i += 3) {
			vertices[i] = vertices[i] + centerX;
			vertices[i + 1] = vertices[i + 1] + centerY;
		}
	}
}
